#!/usr/bin/python3
# -*- coding: utf-8 -*-
import time
import threading
import collections

try:
    import Tkinter as tk  # Python 2
except ImportError:
    import tkinter as tk  # Python 3

TIME_FORMAT = "%y/%m/%d %H:%M:%S"
INTERVAL = 2
'''
cat /proc/stat
cpu번호      user모드      nice user모드    system모드      idle 상태
---------------------------------------------------------------------
cpu           1714278               9666        631901      135528477
cpu0           842765               5302        372331       67721763
cpu1           871513               4364        259570       67806714

cpu 전체값 = (user모드+nice user 모드+system 모드+idle 상태)
user 모드 사용율 = (user 모드)*100 / cpu 전체값
user 모드 사용율 = (user모드 / cpu 전체값) * 100
system 모드 사용율 = (system 모드 / cpu 전체값) * 100

'''
ntCoreUsage = collections.namedtuple('usage', 'name user nice system idle')


def get_stat_list():
    cpulist = []
    f = open("/proc/stat", "r")

    for line in f:
        line = line.replace('  ', ' ')
        vals = line.split(" ")
        if vals[0].startswith('cpu'):
            core = ntCoreUsage(vals[0], int(vals[1]), int(vals[2]), int(vals[3]), int(vals[4]))
            cpulist.append(core)

    f.close()
    return cpulist


def diff_list(list1, list2):
    list3 = []
    for i in range(len(list1)):
        i1 = list1[i]
        i2 = list2[i]
        i3 = ntCoreUsage(i1[0], i1[1] - i2[1], i1[2] - i2[2], i1[3] - i2[3], i1[4] - i2[4])
        list3.append(i3)
    return list3


def hsvToRGB(h, s, v):
    """Convert HSV color space to RGB color space
    @param h: Hue
    @param s: Saturation
    @param v: Value
    return (r, g, b)
    """
    import math
    hi = math.floor(h / 60.0) % 6
    f = (h / 60.0) - math.floor(h / 60.0)
    p = v * (1.0 - s)
    q = v * (1.0 - (f * s))
    t = v * (1.0 - ((1.0 - f) * s))
    return {
        0: (v, t, p),
        1: (q, v, p),
        2: (p, v, t),
        3: (p, q, v),
        4: (t, p, v),
        5: (v, p, q),
    }[hi]


def rgbToHSV(r, g, b):
    """Convert RGB color space to HSV color space
    @param r: Red
    @param g: Green
    @param b: Blue
    return (h, s, v)
    """
    maxc = max(r, g, b)
    minc = min(r, g, b)
    colorMap = {
        id(r): 'r',
        id(g): 'g',
        id(b): 'b'
    }
    h = 0
    if colorMap[id(maxc)] == colorMap[id(minc)]:
        h = 0
    elif colorMap[id(maxc)] == 'r':
        h = 60.0 * ((g - b) / (maxc - minc)) % 360.0
    elif colorMap[id(maxc)] == 'g':
        h = 60.0 * ((b - r) / (maxc - minc)) + 120.0
    elif colorMap[id(maxc)] == 'b':
        h = 60.0 * ((r - g) / (maxc - minc)) + 240.0
    v = maxc
    if maxc == 0.0:
        s = 0.0
    else:
        s = 1.0 - (minc / maxc)
    return (h, s, v)


class MyTimer(object):
    def __init__(self, interval, function, *args, **kwargs):
        self._timer = None
        self.interval = interval
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.is_running = False
        self.start()

    def _run(self):
        self.is_running = False
        self.start()
        self.function(*self.args, **self.kwargs)

    def start(self):
        if not self.is_running:
            self._timer = threading.Timer(self.interval, self._run)
            self._timer.start()
            self.is_running = True

    def stop(self):
        self._timer.cancel()
        self.is_running = False


class LineGraph(tk.Canvas):
    '''A standard canvas widget with a gradient background'''
    def __init__(self, *args, **kwargs):
        tk.Canvas.__init__(self, *args, **kwargs)
        self._color1 = "red"
        self._color2 = "black"
        self._axis = "x"
        self.data = list([0.0, ])
        self.bind("<Configure>", self._draw_gradient)

    def set_axis(self, axis):
        '''Set the axis along which the gradient should be drawn
        axis must be "x" or "y"
        '''
        if axis.lower() not in ("x", "y"):
            raise Exception("axis must be 'x' or 'y'")
        self._axis = axis.lower()

    def set_colors(self, color1, color2):
        '''Set the colors used for the gradient'''
        self._color1 = color1
        self._color2 = color2

    def add_data(self, val):
        while len(self.data) > self.winfo_width():
            self.delete(self.data.pop(0))
        for itm in self.data:
            self.move(itm, 1, 0)
        self.data.append(self.draw_line(val))

    def draw_line(self, val):
        width = self.winfo_width()
        height = self.winfo_height()

        (r1, g1, b1) = self.winfo_rgb(self._color1)
        (r2, g2, b2) = self.winfo_rgb(self._color2)

        r_ratio = float(r2 - r1) / 100.0
        g_ratio = float(g2 - g1) / 100.0
        b_ratio = float(b2 - b1) / 100.0

        nr = int(r1 + (r_ratio * val))
        ng = int(g1 + (g_ratio * val))
        nb = int(b1 + (b_ratio * val))

        color = "#%4.4x%4.4x%4.4x" % (nr, ng, nb)
        # print(h_ratio, s_ratio, v_ratio, rgb, hsv1, hsv2, color, val)
        if self._axis == "y":
            p = val * width / 100.0
            return self.create_line(0, 0, p, 0, fill=color)
        else:
            p = val * height / 100.0
            return self.create_line(0, 0, 0, p, fill=color)

    def _draw_gradient(self, event=None):
        '''Draw the gradient
        N.B. this takes from 2-70ms to complete, depending on the
        size of the canvas
        self.delete("all")
        width = self.winfo_width()
        height = self.winfo_height()

        if self._axis == "x":
            limit = width
        else:
            limit = height

        (r1, g1, b1) = self.winfo_rgb(self._color1)
        (r2, g2, b2) = self.winfo_rgb(self._color2)
        r_ratio = float(r2 - r1) / limit
        g_ratio = float(g2 - g1) / limit
        b_ratio = float(b2 - b1) / limit

        for i in range(len(self.data)):
            nr = int(r1 + (r_ratio * i))
            ng = int(g1 + (g_ratio * i))
            nb = int(b1 + (b_ratio * i))

            color = "#%4.4x%4.4x%4.4x" % (nr, ng, nb)
            if self._axis == "y":
                p = self.data[i] * width / 100.0
                self.create_line(0, i, p, i, fill=color)
            else:
                p = self.data[i] * height / 100.0
                self.create_line(i, 0, i, p, fill=color)
        # self.lower("gradient")
        '''
        pass


class MyMonApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.graph = LineGraph(self, width=100, height=50)
        self.graph.pack(side=tk.TOP, fill=tk.X, expand=False)
        self.graph.set_axis("x")
        self.graph.set_colors("#00ff00", "#ff0000")
        self.core_data = get_stat_list()
        self.timer = MyTimer(1, self.update_data)

    def update_data(self):
        temp_data = list(self.core_data)
        self.core_data = get_stat_list()
        diff_data = diff_list(self.core_data, temp_data)

        for ii in range(len(diff_data)):
            itm = diff_data[ii]
            cpu_usage = 100.0 - (itm.idle * 100.0 / (itm[1] + itm[2] + itm[3] + itm[4]))
            if ii == 0:
                self.graph.add_data(cpu_usage)

    def exit(self):
        self.timer.stop()

if __name__ == "__main__":
    app = MyMonApp()
    app.mainloop()
    app.exit()
